#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <limits.h>
#include <math.h>

#include "table.h"
#include "cstring.h"

IString String = {
	.new       = __string_new,
	.format    = __string_format,
	.len       = __string_length,
	.print     = __string_print,
	.input     = __string_input,
	.readfile  = __string_readfile,
	.readline  = __string_readline,
	.writefile = __string_writefile,
	.reverse   = __string_reverse,
	.sub       = __string_sub,
	.find      = __string_find,
	.findchar  = __string_findchar,
	.concat    = __string_concat,
	.rep       = __string_rep,
	.equals    = __string_equals,
	.compare   = __string_compare,
	.fromchar  = __string_fromchar,
	.fromint   = __string_fromint,
	.fromfloat = __string_fromfloat,
	.toint     = __string_toint,
	.tofloat   = __string_tofloat,
	.del       = __string_del,
	.gc        = __string_gc,
	.freeall   = __string_freeall,
}; // 提供标准实现

static table __string_pool = {}; // 字符串常量池

#define str_pool_query(chs) (var_string)tb_get(__string_pool, chs)
#define str_pool_save(str) tb_set(__string_pool, str->cstr, str)


#define var_string struct __struct_of_string* // 仅内部使用的可变字符串

#define str_alloc(len) (struct __struct_of_string *)malloc(sizeof(struct __struct_of_string) + (len) + 1)

// 内部统一字符串创建接口
static inline var_string __string_newInstance(const char* chars, size_t length) {
	struct __struct_of_string *str = str_alloc(length);
	str->length = length;
	str->gcmark = 0;
	memcpy(str->cstr, chars, length);
	str->cstr[length] = '\0';
	return str;
}

static inline var_string __string_newNullstr(size_t length) {
	struct __struct_of_string *str = str_alloc(length);
	str->length = length;
	str->gcmark = 0;
	str->cstr[0] = '\0';
	return str;
}


// String.new
string __string_new(const char* chars) {
	if (!chars) return NULLSTR;
	
	var_string str = str_pool_query(chars);
	if (str) {
		str->gcmark = 0;
		return str;
	}
	
	size_t length = strlen(chars);
	str = __string_newInstance(chars, length);

	str_pool_save(str);
	return str;
}


// String.len
size_t __string_length(string str) {return str->length;}
// String.print
void __string_print(string str) {puts(str->cstr);}


// String.input
string __string_input(char* hint) {
	if (hint && *hint) // 有提示信息 (不是NULL, 也不是空串)
		fputs(hint, stdout);
	
	char prebuf[1024], *buf = prebuf;
	if (!fgets(buf, sizeof(prebuf), stdin))
		return NULLSTR;
	
	char* eoi = strchr(buf, '\n'); // 靠换行符定位结尾
	
	if (eoi) { // 如果读取了换行符
		*eoi = '\0'; // 去掉换行符
	} else { // 如果未能读取换行符
		eoi = buf + sizeof(prebuf) - 1; // 重新定位字符串末尾
		int ch;
		while ((ch=getchar()) != '\n' && ch != EOF); //清理 stdin 中残留的字符
	}
	
	string inpt = str_pool_query(buf);
	if (inpt) return inpt;
	
	size_t length = eoi - buf;
	inpt = __string_newInstance(buf, length);
	
	str_pool_save(inpt);
	return inpt;
}


// String.readfile
string __string_readfile(FILE* fp) {
	if (!fp) return NULLSTR; // 没有文件返回空字符串
	fseek(fp, 0, SEEK_END);
	long size = ftell(fp);

	if (size <= 0) return NULLSTR; // 文件为空返回空字符串

	fseek(fp, 0, SEEK_SET);
	char chars[size+1];
	chars[size] = '\0';
	fread(chars, 1, size, fp);

	var_string str = str_pool_query(chars);
	if (str) {
		str->gcmark = 0;
		return str;
	}

	str = __string_newInstance(chars, size);
	str_pool_save(str);
	return str;
}


// 不是我写的，待审查
string __string_readline(FILE* fp) {
	if (!fp) return NULLSTR;
	char prebuf[1024], *buf = prebuf;
	if (!fgets(buf, sizeof(prebuf), fp))
		return NULLSTR;
	
	char* eoi = strchr(buf, '\n'); // 靠换行符定位结尾
	
	if (eoi) { // 如果读取了换行符
		*eoi = '\0'; // 去掉换行符
	} else { // 如果未能读取换行符
		eoi = buf + sizeof(prebuf) - 1; // 重新定位字符串末尾
		int ch;
		while ((ch=getc(fp)) != '\n' && ch != EOF); //清理文件中残留的字符
	}
	
	var_string str = str_pool_query(buf);
	if (str) {
		str->gcmark = 0;
		return str;
	}

	size_t length = eoi - buf;
	str = __string_newInstance(buf, length);
	str_pool_save(str);
	return str;
}


// String.writefile
int __string_writefile(FILE* fp, string str) {
	if (!fp || !str) return 0;
	return fwrite(str->cstr, 1, str->length, fp) == str->length;
}


// String.reverse
string __string_reverse(string str) {
	var_string rts = __string_newNullstr(str->length);

	for (size_t i = 0; i < str->length; i++)
		rts->cstr[i] = str->cstr[str->length-1-i];
	rts->cstr[str->length] = '\0';
	
	var_string intern = str_pool_query(rts->cstr);
	if (intern) {
		free(rts);
		intern->gcmark = 0;
		return intern;
	}
	
	str_pool_save(rts);
	return rts;
}


// String.sub
string __string_sub(string str, size_t start_idx, size_t end_idx) {
	if (start_idx > end_idx || end_idx > str->length)
		return NULLSTR; // 非法区间

	if (start_idx == 0 && end_idx == str->length)
		return str; // 等于自身

	size_t length = end_idx - start_idx;
	var_string sub = __string_newInstance(str->cstr + start_idx, length);
	
	var_string intern = str_pool_query(sub->cstr);
	if (intern) {
		free(sub);
		intern->gcmark = 0;
		return intern;
	}
	
	str_pool_save(sub);
	return sub;
}


// String.format
string __string_format(const char *fmt, ...) {
	va_list args, cpy;
	va_start(args, fmt);
	
	// 估计缓冲区大小
	size_t b_size = strlen(fmt)*2;
	b_size = b_size > 1024? b_size: 1024;
	
	char prebuf[b_size], *buf = prebuf;
	size_t needlen;

	for(;;) {
		va_copy(cpy,args);
		needlen = vsnprintf(buf, b_size, fmt, cpy);
		va_end(cpy);
		
		// 格式错误或写入失败
		if (needlen < 0) {
			if (buf != prebuf) free(buf);
			return NULLSTR;
		}
		
		// 缓冲区不够，重新分配
		if (needlen >= b_size) {
			if (buf != prebuf) free(buf);
			b_size = needlen + 1;
			buf = (char*)malloc(b_size);
			if (buf == NULL) return NULLSTR;
			continue;
		}
		break;
	}

	var_string str = str_pool_query(buf);
	if (str) {
		if (buf != prebuf) free(buf);
		str->gcmark = 0;
		return str;
	}
	
	str = __string_newInstance(buf, needlen);
	str_pool_save(str);
	if (buf != prebuf) free(buf);
    return str;
}


// String.find
size_t __string_find(string str, string sub) {
	char* adss = strstr(str->cstr, sub->cstr);
	if (!adss) return 0;
	return adss-(str->cstr);
}


// String.findchar
size_t __string_findchar(string str, char cub) {
	char* adss = strchr(str->cstr, cub);
	if (!adss) return 0;
	return adss-(str->cstr);
}


// String.concat
string __string_concat(string pre, string suf) {
	// 空字符串无需进行连接
	if (pre->length == 0) return suf;
	if (suf->length == 0) return pre;
	
	size_t length = pre->length + suf->length;
	var_string str = __string_newNullstr(length);
	
	memcpy(str->cstr, pre->cstr, pre->length);
	memcpy(str->cstr + pre->length, suf->cstr, suf->length);
	str->cstr[length] = '\0';
	
	var_string intern = str_pool_query(str->cstr);
	if (intern) {
		free(str);
		intern->gcmark = 0;
		return intern;
	}
	
	str_pool_save(str);
	return str;
}


// String.rp
string __string_rep(string str, uint32_t count) {
	if (count == 0) return NULLSTR;
	if (count == 1) return str;

	size_t length = str->length * count;
	var_string rep = __string_newNullstr(length);

	for (size_t i = 0; i < count; i++)
		memcpy(rep->cstr + i*str->length, str->cstr, str->length);
	rep->cstr[length] = '\0';
	
	var_string intern = str_pool_query(rep->cstr);
	if (intern) {
		free(rep);
		intern->gcmark = 0;
		return intern;
	}
	
	str_pool_save(rep);
	return rep;
}


// Sting.equals
int __string_equals(string s1, string s2) {
	if (s1 == s2) return 1; // 同一个对象一定相等
	if (s1->length != s2->length) return 0; // 长度不等一定不等
	return !memcmp(s1->cstr, s2->cstr, s1->length); // 长度不等则比较字符差异
}


// String.compare
int __string_compare(string s1, string s2) {
	if (s1 == s2) return 0; // 同一个对象一定相等
	size_t n = s1->length > s2->length? s2->length: s1->length;
	return memcmp(s1->cstr, s2->cstr, n + 1);
	// 如果长度相同，则 s1 s2 在 n+1 处都是空字符，恰好比较到结尾
	// 如果长度不同，则 n+1 一定是第一个不同的字符，因为有一个是空字符另一个不是
}


// String.fromchar
string __string_fromchar(char ch) {
	char buf[2] = {ch, '\0'};
	var_string str = str_pool_query(buf);
	if (str) {
		str->gcmark = 0;
		return str;
	}
	str = __string_newInstance(buf, 1);
	str_pool_save(str);
	return str;
}


// String.fromint
string __string_fromint(long num) {
	char buf[32];
	int len = snprintf(buf, sizeof(buf), "%ld", num);
	if (len < 0 || len >= sizeof(buf)) return NULLSTR;

	var_string str = str_pool_query(buf);
	if (str) {
		str->gcmark = 0;
		return str;
	}

	str = __string_newInstance(buf, len);
	str_pool_save(str);
	return str;
}


// String.fromfloat
string __string_fromfloat(double num) {
	char buf[64];
	int len = snprintf(buf, sizeof(buf), "%.16g", num);
	if (len < 0 || len >= sizeof(buf)) return NULLSTR;
	
	var_string str = str_pool_query(buf);
	if (str) {
		str->gcmark = 0;
		return str;
	}

	str = __string_newInstance(buf, len);
	str_pool_save(str);
	return str;
}


// String.toint
long __string_toint(string str) {
	if (!str || !str->length || *str->cstr > '9') {
		errno = EINVAL;
		return 0;
	} /* 快速排除非数字字符串
	因为 9 是 (0-9 + - .) 中最大的字符 */
	
	char *end;
	long num = strtol(str->cstr, &end, 0);
	
	if (end == str->cstr || *end != '\0') {
		errno = EINVAL;
		return 0;
	}
	
	if (errno == ERANGE && num) {
		return num > 0? LONG_MAX: LONG_MIN;
	}
	
	return num;
}


// String.tofloat
double __string_tofloat(string str) {
	if (!str || !str->length || *str->cstr > '9') {
		errno = EINVAL;
		return 0.0;
	}
	
	char *end;
	double num = strtod(str->cstr, &end);
	
	if (end == str->cstr || *end != '\0') {
		errno = EINVAL;
		return 0.0;
	}
	
	if (errno == ERANGE && num != 0.0) {
		return num > 0? HUGE_VAL: -HUGE_VAL;
	}
	
	return num;
}


// String.del
void __string_del(string str) {
	if (str->gcmark) return;
	var_string str_mod = (var_string)str;
	str_mod->gcmark = 1;
}


// String.gc
void __string_gc() {
	for (kvp* in_pairs(__string_pool, kv))
		if (((string)(kv->val))->gcmark) {
			free(kv->val); // 释放对象内存
			kvp_unset(kv); // 从池中解绑
		}
}


// String.freeall
void __string_freeall() {
	for (kvp* in_pairs(__string_pool, kv)) {
		free(kv->val);
		kvp_unset(kv);
	}
}



// 结束内部宏的作用域
#undef str_pool_query
#undef str_pool_save
#undef var_string
#undef str_alloc
